package com.liu.shopcar.controlelr;

import com.liu.shop.common.constant.CarConstants;
import com.liu.shop.common.exception.BusinessException;
import com.liu.shop.common.utils.R;
import com.liu.shop.common.vo.GoodsVo;
import com.liu.shop.common.vo.StoreVo;
import com.liu.shopcar.feign.GoodsVoServices;
import com.liu.shopcar.interceptor.UserCarInterceptor;
import com.liu.shopcar.vo.CarVo;
import com.liu.shopcar.vo.StoreCarVo;
import com.liu.shopcar.vo.UserCarVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.*;

@Controller
@RequestMapping("/shopcar")
@Slf4j
public class CarController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private GoodsVoServices goodsVoServices;

    // 前置过滤器，对用户是否登录进行判断，并返回一个id或者uuid
    @Autowired
    private UserCarInterceptor userCarInterceptor;

    /**
     * 添加商品信息到redis中
     *
     * @param carvo
     * @param session
     * @return
     */
    @RequestMapping("/add")
    @ResponseBody
    public R add(@RequestBody CarVo carvo, HttpSession session) {
        // 获取当前用户的的id
        String userCarId = userCarInterceptor.get();
        System.out.println("新添加的商品信息为：" + carvo);
        // 使用hash存如到redis中。
        // redis中hash的存值结构：    kay         filed       value
        //                         uuid/uid       商品id      数量
        // hash绑定
        BoundHashOperations<String, Object, Object> carHashMap =
                stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + userCarId);

        // 将商铺id和该商铺下的商品绑定在一起
        String filed = carvo.getSid() + ":" + carvo.getGid();

        // 获得value
        String val = carvo.getCount().toString();

        carHashMap.increment(filed, Long.parseLong(val));
        return R.ok();
    }

    /**
     * 获取用户购物车商品总数量
     *
     * @return
     */
    @GetMapping("/getUserCarCount")
    @ResponseBody
    public Integer getUserCarCount(HttpServletRequest request) {
        return getUserCarVo(null).getSize();
    }

    /**
     * 将用户购物车中的所有信息返回给视图
     * 基本信息，库存，商铺信息
     * @param modelMap
     * @return
     */
    @GetMapping("/getUserCarList")
    public String getUserCarList(ModelMap modelMap) {
//        // 创建一个集合用来存放购物车中的所有商品信息
//        List<CarVo> carList = new ArrayList<>();
//
//        // 1.获取用户购物车的id，用来查询购物车中商品的基本信息
//        String userCarId = userCarInterceptor.get();
//
//        // 2.绑定
//        BoundHashOperations<String, Object, Object> hashOperations =
//                stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + userCarId);
//
//        // 3.获取所有商品id和库存
//        Set<Object> keys = hashOperations.keys();
//        for (Object key : keys) {
//
//            // 获取商品id
//            String gidStr = key.toString().split(":")[1];
//
//            int gid = Integer.parseInt(gidStr.toString());
//            int count = Integer.parseInt((hashOperations.get(key).toString()));
//
//            CarVo carVo = new CarVo();
//            carVo.setGid(gid);
//            carVo.setCount(count);
//
//            // 调用商品模块按id查询s
//            GoodsVo goodsVo = goodsVoServices.getGoodsVoById(gid);
//            carVo.setGoodsVo(goodsVo);
//
//            //商品总价 （价格*数量）
//            BigDecimal totalPrices = goodsVo.getGprice().multiply(BigDecimal.valueOf(count));
//            carVo.setTotalPrices(totalPrices);
//
//            // 将所有商品信息存放到集合中
//            carList.add(carVo);
//        }
//        System.out.println("购物车商品信息："+carList);
//        modelMap.put("carList", carList);
//        return "carList"; // 返回的视图名称
        modelMap.put("userCarVo", getUserCarVo(null));
        return "carList"; // 返回的视图名称
    }

    /**
     * 获取购物车中的所有信息
     * @return
     */
    public UserCarVo getUserCarVo(Set<Object> keyList) {

        // 最终返回给前端的购物车对象
        UserCarVo userCarVo = new UserCarVo();

        // 创建集合，将所有的商品信息（基本信息，商品数量，商品总价，状态）存入其中
        List<CarVo> carVoList = new ArrayList<>();
        Set<Object> keys = null;

        // 1.获取用户购物车的id，登录就是uid，未登录就是uuid，存在redis中
        String userCarId = userCarInterceptor.get();

        // 2.通过key，获取在redis中的filed（商品id）和value（商品数量）
        BoundHashOperations<String, Object, Object> hashOperations = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + userCarId);

        // 用户勾选将要购买的商品集合
        if (keyList == null || keyList.isEmpty()) {
            // 3.获取所有商品id
            keys = hashOperations.keys();
        } else {
            keys = keyList;
        }


        // 定义总价（单个商品的数量X商品单价）
        BigDecimal totalPrice = new BigDecimal(0.0);

        // 遍历每一个key（filed：商品id）
        for (Object key : keys) {

            // 获取商品ID
            // 存储时商品和商铺进行绑定，所用格式为(sid:gid)
            String gIdStr = key.toString().split(":")[1];

            int gid = Integer.parseInt(gIdStr.toString());
            // 通过filed获取该件商品的购买数量
            int count = Integer.parseInt(hashOperations.get(key).toString());

            // 创建一个新的购物车
            CarVo carVo = new CarVo();
            carVo.setGid(gid);
            carVo.setCount(count);
            // 根据商品Id查询商品基本信息
            GoodsVo goodsVo = goodsVoServices.getGoodsVoById(gid);
            carVo.setGoodsVo(goodsVo);

            // 计算每个购物车中商品的价格（商品单价*该商品数量）
            BigDecimal totalPrices = goodsVo.getGprice().multiply(BigDecimal.valueOf(count));
            carVo.setTotalPrices(totalPrices);

            carVoList.add(carVo);

            // 付款总价=所有的小计累加
            totalPrice = totalPrice.add(totalPrices);
        }

        // 创建一个商铺的集合
        List<StoreCarVo> storeCarVoList = new ArrayList<>();

        // 准备一个set用来去重，因为购物车中的多个商品可能来自同一家店铺。
        Set<StoreVo> storeVoSet = new HashSet<>();
        // 把所有的商品中的商铺取出来
        for (CarVo carVo : carVoList) {
            storeVoSet.add(carVo.getGoodsVo().getStoreVo());
        }

        // 把去重后的商铺放到storeCarVoSet
        for (StoreVo storeVo : storeVoSet) {
            // 将去重后的店铺id和名字放入到各自店铺的购物车中
            StoreCarVo storeCarVo = new StoreCarVo();
            storeCarVo.setStoreVo(storeVo);

            for (CarVo carVo : carVoList) {
                // 获取店铺id
                Integer carSid = carVo.getGoodsVo().getStoreVo().getId();
                // 如果商品的id和店铺的id一致
                if (storeVo.getId() == carSid) {
                    List<CarVo> carVoList1 = storeCarVo.getCarVoList();
                    if (carVoList1 == null) {
                        carVoList1 = new ArrayList<>();
                        carVoList1.add(carVo);
                        storeCarVo.setCarVoList(carVoList1);
                    } else {
                        carVoList1.add(carVo);
                    }
                }
            }
            storeCarVoList.add(storeCarVo);
        }

        // 根据商铺的信息找购物车去
        userCarVo.setStoreCarVoList(storeCarVoList);
        userCarVo.setSize(carVoList.size());
        userCarVo.setTotalPrice(totalPrice);
        return userCarVo;
    }


    /**
     * 商品数量进行动态增减
     * @param car
     * @return
     */
    @PostMapping("/updateCarCount")
    @ResponseBody
    public R updateCarCount(@RequestBody CarVo car) {
        // 获取购物车id
        String userCarId = userCarInterceptor.get();

        // 根据用户id查找在redis中对应的hash
        BoundHashOperations<String, Object, Object> carMap = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + userCarId);
        String filed = car.getSid().toString() + ":" + car.getGid();

        // 先查询购物车中商品的数量
        Integer count = Integer.parseInt(carMap.get(filed).toString());

        // 获得商品id
        // 判断自增还是自减
        switch (car.getStatus()) {
            case "add":
                // 判断库存是否足够
                // 1.先获取库存数量
                GoodsVo goodsVo = goodsVoServices.getGoodsVoById(car.getGid());
                Integer stock = goodsVo.getStock();
                if(stock<=count){
                    throw new BusinessException("库存不足",504);
                }
                carMap.increment(filed, 1); // 根据商品id（key）进行数量（value）的加一
                break;
            case "sub":
                // 判断商品数量不能减到0
                if (count <= 1) {
                    throw new BusinessException("购买的数量不能小于0", 504);
                }
                carMap.increment(filed, -1); //减一
                break;
        }
        return R.ok();

    }
    @GetMapping("/delCar/{sid}/{gid}")
    @ResponseBody
    public R delCar(@PathVariable String sid, @PathVariable String gid) {
        String userCarId = userCarInterceptor.get();
        String filed = sid+":"+gid;
        stringRedisTemplate.opsForHash().delete(CarConstants.CAR_PRE + userCarId, filed);
        return R.ok();
    }

    /**
     * 动态加减总价
     * @param sgid
     * @return
     */
    @PostMapping("/carSelectGoods")
    @ResponseBody
    public R carSelectGoods(@RequestBody List<String> sgid) {
        //关键数据：获取商品的总数量（count），商品的单价（price）

        // 1.获取用户的购物车id
        String userCarId = userCarInterceptor.get();
        // 2.获取用户购物车中的信息
        BoundHashOperations<String, Object, Object> carMap = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + userCarId);

        // 初始化总价
        BigDecimal totalPrice = new BigDecimal(0.0);
        // 遍历前端穿过来的商品id和店铺id（sid:gid）数组
        for (String key : sgid) {
            // 切割filed得到商品id和店铺id
            String[] s = key.split(":");
            Integer sid = Integer.parseInt(s[0]);
            Integer gid = Integer.parseInt(s[1]);

            // 根据field获取商品的数量
            Integer count = Integer.parseInt(carMap.get(key).toString());
            // 调用商品模块拿取商品单价
            GoodsVo goodsVo = goodsVoServices.getGoodsVoById(gid);
            BigDecimal gprice = goodsVo.getGprice(); // 商品价格

            // 计算总价
            totalPrice = totalPrice.add(gprice.multiply(BigDecimal.valueOf(count)));
        }
        return R.ok().put("totalPrice", totalPrice);
    }

    /**
     * 合并购物车，提供接口给订单页面使用
     * 用户登录成功后将原来没有登录时的购物车信息加到登录后的购物车信息中
     */
    @GetMapping("/mergeCar")
    @ResponseBody
    public R mergeCar(String uid) {

        // 获取当前的request对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取匿名用户购物车的key
        Cookie[] cookies = request.getCookies();
        // 先进行cookie判断，保证没有登录的用户有加入购物车的记录
        if(cookies!=null&& cookies.length>0) {
            String val = null;
            for (Cookie cookie : cookies) {
                // 获取cookie中的name
                String name = cookie.getName();
                // 判断未登录的用户cookie是否存在
                if (CarConstants.CAR_ANON_NAME.equals(name)) {
                    // 获取value
                    val = cookie.getValue();
                    break;
                }
            }
            //
            if (!StringUtils.isEmpty(val)) {
                // 绑定未登录的购物车
                BoundHashOperations<String, Object, Object> annonCarMap = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + val);
                // 判断未登录的购物车中是否有商品信息
                if (annonCarMap != null && annonCarMap.size() > 0) {
                    // 绑定登录后的购物车
                    BoundHashOperations<String, Object, Object> loginCarMap = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + uid);

                    // 将未登录的用户购物车商品信息，拷贝到登录后的用户购物车商品信息中
                    Map<Object, Object> entries = annonCarMap.entries();
                    for (Map.Entry<Object, Object> entry : entries.entrySet()) {
                        String key = entry.getKey().toString(); // field（商铺id:商品id）
                        Long value = Long.parseLong(entry.getValue().toString()); // value（商品数量）
                        loginCarMap.increment(key, value);
                    }
                    // 清空购物车
                    stringRedisTemplate.delete(CarConstants.CAR_ANON_NAME + val);
                }
            }
        }
        return R.ok();
    }

    // 返回用户指定的购车的信息
    @PostMapping("/getUserCar")
    @ResponseBody
    public UserCarVo getUserCar(String key) {
        String[] split = key.split(",");
        Set<Object> set = new HashSet<>();
        for (String s : split) {
            set.add(s);
        }
        log.debug("keyList:{}", key);
        return getUserCarVo(set);
    }

    /**
     * 根据用户下单的商品信息进行删除购物车中的信息
     * @param uid
     * @param selectGid
     */
    @GetMapping("/clearUserCar")
    @ResponseBody
    void clearUserCar(@RequestParam("uid") String uid, @RequestParam("selectGid") String selectGid){
        BoundHashOperations<String, Object, Object> hashOperations = stringRedisTemplate.boundHashOps(CarConstants.CAR_PRE + uid);
        hashOperations.delete(selectGid.split(","));
    }
}
